package com.yoofn.framework.http

import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.Log
import com.yanzhenjie.nohttp.NoHttp
import com.yanzhenjie.nohttp.rest.OnResponseListener
import com.yanzhenjie.nohttp.rest.Response
import com.yoofn.framework.debug.DebugConfig

/**
 * Created by kalshen on 2017/7/20.
 * @描述 项目网络请求框架封装
 */
interface IHttpFramework {


    /**
     * 增加单个或多个网络请求
     * @param httpNetData 网络请求参数
     */
    fun addRequest(vararg httpNetData: HttpNetData) {
        if(httpNetData.isEmpty()) return
        initNetParams(*httpNetData)
    }


    /**
     * 配置网络请求request 和 resp
     * @param httpNetData 网络请求实体对象
     */
    private fun initNetParams(vararg httpNetData: HttpNetData) {


        //如果请求数量大于2 则创建一个新打请求队列,长度为请求数量
        //如果请求数量小于2 则使用单例请求队列
        val newRequestQueue = if (httpNetData.size > 2) NoHttp.newRequestQueue(httpNetData.size) else NoHttp.getRequestQueueInstance()

        httpNetData.forEach {

            //统一处理request
            unifiedProcessing(it)
            //将请求加入请求队列
            newRequestQueue.add<String>(it.what, it.request, object : OnResponseListener<String> {

                //请求开始时
                override fun onStart(p0: Int) {
                    //打印网络日志
                    printHttpStartCatchLog(it, p0)
                    //网络请求前需要处理的事物
                    actionBeforeRequestStart(it)
                    //请求开始前 实现类自身的逻辑业务
                    onRequestStart(p0)
                }

                //请求结束后
                override fun onFinish(p0: Int) {
                    //网络请求结束后需要处理的事物
                    actionAfterRequestFinish(it)
                    //请求结束后 实现类自身的逻辑业务
                    onRequestFinished(p0, httpNetData.filter { !it.request.isFinished })
                }

                //请求成功时
                override fun onSucceed(p0: Int, p1: Response<String>?) {
                    //打印网络日志
                    printHttpSuccessCatchLog(p0)
                    //请求成功后需要处理的事物
                    actionAfterRequestSuccess(it, p1, p0)
                }

                //请求失败时
                override fun onFailed(p0: Int, p1: Response<String>?) {
                    //打印网络日志
                    printHttpFailedCatchLog()
                    //TODO 这里可以优化统一请求失败后的结果
                    //请求失败后 实现类自身的逻辑业务
                    onRequestFailed(p0, p1)
                }
            })
        }
    }

    /**
     * 统一处理 http请求对象
     */
    fun unifiedProcessing(httpNetData: HttpNetData?) {
        when (httpNetData) {
        //token netData
            is HttpTokenNetData -> {
                httpNetData.addToken()
            }
            else -> {
            }
        }

    }


    fun actionAfterRequestSuccess(httpNetData: HttpNetData?, response: Response<String>?, what: Int) {
        response?.let {
            if (it.isSucceed) {
                when (httpNetData) {
                //token netData
                    is HttpTokenNetData -> {
                        //同步本地缓存中的 access-token
                        httpNetData.syncLocalToken(response)
                    }
                }

                //将网络回调 执行到主线程去
                Handler(Looper.getMainLooper()).post { doBusiness(what, it) }
            }
        }
    }


    /**
     * 有需要在请求结束后做的一些操作
     * @param httpNetData Http请求二次封装对象(request)
     */
    fun actionAfterRequestFinish(httpNetData: HttpNetData) {
        httpNetData.dialog?.dismiss()
        httpNetData.actionView?.isEnabled = true
    }

    /**
     * 有需要在请求开始前做的一些操作,比如：可能请求需要统一添加token 等
     * @param httpNetData Http请求二次封装对象(request)
     */

    fun actionBeforeRequestStart(httpNetData: HttpNetData) {
        //避免反复请求，将触发请求的view设为 enable = false
        httpNetData.actionView?.isEnabled = false
        //fixme 这里默认没有dialog 只有用户传入的时候才会显示 如果需求每一个请求都需要dialog 这里可以给出默认的dialog
        httpNetData.dialog?.show()
    }


    /**
     * 打印网络请求开始时的请求参数
     * @param httpNetData Http请求二次封装对象(request)
     * @param what 用于区分请求
     */

    fun printHttpStartCatchLog(httpNetData: HttpNetData, what: Int) {
        val tag = DebugConfig.HTTP_CATCH_SIMPLE_LOG_TAG
        if (DebugConfig.IS_ENABLE_REQUEST_LOG) {
            val paramKeyValues = httpNetData.request.paramKeyValues
            val info = StringBuilder()
            paramKeyValues.entrySet().forEach { info.append("\n${it.key}:${it.value}") }
            Log.d(tag, "--------------Request start    What: [[ $what ]]--------------")
            Log.i(tag, "Request address:${httpNetData.request.url()}")
            Log.i(tag, "Request method:${httpNetData.request.requestMethod}")
            Log.i(tag, "Content-Type:${httpNetData.request.contentType}")
            Log.i(tag, "Request-Type:${httpNetData.request::class.java.simpleName}")
            Log.i(tag, "params：${if (TextUtils.isEmpty(info.toString())) "empty" else info.toString()}")
        }
    }

    /**
     * 打印网络请求成功时的日志
     */
    fun printHttpSuccessCatchLog(what: Int) {
        if (DebugConfig.IS_ENABLE_RESPONSE_LOG) {
            val tag = DebugConfig.HTTP_CATCH_SIMPLE_LOG_TAG
            Log.e(tag, "--------------Response success   What: [[ $what ]]--------------")

        }
    }

    /**
     * 打印网络请求失败后的日志
     */
    fun printHttpFailedCatchLog() {
        if (DebugConfig.IS_ENABLE_RESPONSE_LOG) {
            val tag = DebugConfig.HTTP_CATCH_SIMPLE_LOG_TAG
            Log.e(tag, "--------------Response error--------------")
            Log.e(tag, "error: con't access to remote server")
        }
    }

    /**
     * 用于实现类完成自身的逻辑业务
     * 请求开始
     */
    fun onRequestStart(what: Int) {

    }

    /**
     * 用于实现类完成自身的逻辑业务
     * 请求结束
     * @param what
     * @param unFinishedNetData 还没请求结束的netData 集合
     */
    fun onRequestFinished(what: Int, unFinishedNetData: List<HttpNetData?>) {

    }

    /**
     * 用于实现类完成自身的逻辑业务
     * 请求失败
     */
    fun onRequestFailed(what: Int, response: Response<String>?) {

    }

    /**
     * 用于处理业务逻辑(网络访问已经成功)
     * @param what 区别网络请求
     * @param response 请求返回经过类型处理的的response.get()对象
     *                     如果请求是StringRequest 则 返回的responseBody是String
     *                     如果请求是JsonObjectRequest 则 返回的responseBody是JsonObject
     *                     这个返回类型是根据 {@link HttpNetData} 类中的的 request 泛型决定
     */
    fun doBusiness(what: Int, response: Response<String>)
}